// mythread.cc
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include "LockGuard.hpp"
using namespace std;


// 新线程个数，主线程不参与抢票
#define NUM 4

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;  // 全局锁用宏初始化
int tickets = 1000; // 用多线程，模拟一轮抢票

class threadData
{
public:
    threadData(int number/*, pthread_mutex_t *lock*/)
        : _threadname("thread-" + to_string(number))/*, _lock(lock)*/
    {
    }

public:
    string _threadname;
    // pthread_mutex_t *_lock;
};

void *getTicket(void *args)
{
    threadData *td = static_cast<threadData*>(args);
    const char* name = td->_threadname.c_str();
    while (1)
    {
        pthread_mutex_lock(&lock);
        pthread_mutex_lock(&lock);  // 同一把锁申请了两次，就会导致死锁
        if (tickets > 0)
        {
            usleep(1000);  // 抢票花的时间
            printf("%s get a ticket: %d\n", name, tickets);
            tickets--;
            pthread_mutex_unlock(&lock);  // 解锁
        }
        else
        {
            pthread_mutex_unlock(&lock);  // 解锁
            break;
        }
        usleep(13);  // 我们抢到了票，会立马抢下一张吗？不会，其实多线程还要执行得到票之后的后续动作，用usleep模拟
    }
    printf("%s ... quit\n", name);

    return nullptr;
}

int main()
{
    // pthread_mutex_t lock;  // 锁也是一个变量，这是在main函数的栈上开辟的空间
    // pthread_mutex_init(&lock, nullptr);

    vector<pthread_t> tids;
    vector<threadData *> thread_datas;
    for (int i = 1; i <= NUM; ++i)
    {
        pthread_t tid;
        threadData *td = new threadData(i/*, &lock*/);
        thread_datas.push_back(td);

        pthread_create(&tid, nullptr, getTicket, td);
        tids.push_back(tid);
    }

    for (auto thread : tids)
    {
        pthread_join(thread, nullptr);
    }
    for (auto td : thread_datas)
    {
        delete td;
    }

    // pthread_mutex_destroy(&lock);
    return 0;
}





// // 新线程个数，主线程不参与抢票
// #define NUM 4

// pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // 全局锁用宏初始化
// int tickets = 1000;                               // 用多线程，模拟一轮抢票

// class threadData
// {
// public:
//     threadData(int number /*, pthread_mutex_t *lock*/)
//         : _threadname("thread-" + to_string(number)) /*, _lock(lock)*/
//     {
//     }

// public:
//     string _threadname;
//     // pthread_mutex_t *_lock;
// };

// void *getTicket(void *args)
// {
//     threadData *td = static_cast<threadData *>(args);
//     const char *name = td->_threadname.c_str();
//     while (1)
//     {
//         {
//             LockGuard lockguard(&lock); // 局部的LockGuard对象，定义时自动加锁，退出代码块时自动解锁，用对象的生命周期来管理加锁和解锁，这种风格叫做RAII风格的锁
//             if (tickets > 0)
//             {
//                 usleep(1000); // 抢票花的时间
//                 printf("%s get a ticket: %d\n", name, tickets);
//                 tickets--;
//             }
//             else
//             {
//                 break;
//             }
//         }
//         usleep(13); // 我们抢到了票，会立马抢下一张吗？不会，其实多线程还要执行得到票之后的后续动作，用usleep模拟
//     }
//     printf("%s ... quit\n", name);

//     return nullptr;
// }

// int main()
// {
//     // pthread_mutex_t lock;  // 锁也是一个变量，这是在main函数的栈上开辟的空间
//     // pthread_mutex_init(&lock, nullptr);

//     vector<pthread_t> tids;
//     vector<threadData *> thread_datas;
//     for (int i = 1; i <= NUM; ++i)
//     {
//         pthread_t tid;
//         threadData *td = new threadData(i /*, &lock*/);
//         thread_datas.push_back(td);

//         pthread_create(&tid, nullptr, getTicket, td);
//         tids.push_back(tid);
//     }

//     for (auto thread : tids)
//     {
//         pthread_join(thread, nullptr);
//     }
//     for (auto td : thread_datas)
//     {
//         delete td;
//     }

//     // pthread_mutex_destroy(&lock);
//     return 0;
// }






// // 新线程个数，主线程不参与抢票
// #define NUM 4

// pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;  // 全局锁用宏初始化
// int tickets = 1000; // 用多线程，模拟一轮抢票

// class threadData
// {
// public:
//     threadData(int number/*, pthread_mutex_t *lock*/)
//         : _threadname("thread-" + to_string(number))/*, _lock(lock)*/
//     {
//     }

// public:
//     string _threadname;
//     // pthread_mutex_t *_lock;
// };

// void *getTicket(void *args)
// {
//     threadData *td = static_cast<threadData*>(args);
//     const char* name = td->_threadname.c_str();
//     while (1)
//     {
//         // 线程对于锁的竞争能力可能会不同
//         // pthread_mutex_lock(td->_lock);  // 申请锁成功，才能往后执行；不成功，阻塞等待
//         pthread_mutex_lock(&lock);  // 申请锁成功，才能往后执行；不成功，阻塞等待
//         if (tickets > 0)
//         {
//             usleep(1000);  // 抢票花的时间
//             printf("%s get a ticket: %d\n", name, tickets);
//             tickets--;
//             //pthread_mutex_unlock(td->_lock);  // 解锁
//             pthread_mutex_unlock(&lock);  // 解锁
//         }
//         else
//         {
//             //pthread_mutex_unlock(td->_lock);  // 解锁
//             pthread_mutex_unlock(&lock);  // 解锁
//             break;
//         }
//         usleep(13);  // 我们抢到了票，会立马抢下一张吗？不会，其实多线程还要执行得到票之后的后续动作，用usleep模拟
//     }
//     printf("%s ... quit\n", name);

//     return nullptr;
// }

// int main()
// {
//     // pthread_mutex_t lock;  // 锁也是一个变量，这是在main函数的栈上开辟的空间
//     // pthread_mutex_init(&lock, nullptr);

//     vector<pthread_t> tids;
//     vector<threadData *> thread_datas;
//     for (int i = 1; i <= NUM; ++i)
//     {
//         pthread_t tid;
//         threadData *td = new threadData(i/*, &lock*/);
//         thread_datas.push_back(td);

//         pthread_create(&tid, nullptr, getTicket, td);
//         tids.push_back(tid);
//     }

//     for (auto thread : tids)
//     {
//         pthread_join(thread, nullptr);
//     }
//     for (auto td : thread_datas)
//     {
//         delete td;
//     }

//     // pthread_mutex_destroy(&lock);
//     return 0;
// }





// // 新线程个数，主线程不参与抢票
// #define NUM 4

// int tickets = 1000; // 用多线程，模拟一轮抢票

// class threadData
// {
// public:
//     threadData(int number, pthread_mutex_t *lock)
//         : _threadname("thread-" + to_string(number)), _lock(lock)
//     {
//     }

// public:
//     string _threadname;
//     pthread_mutex_t *_lock;
// };

// void *getTicket(void *args)
// {
//     threadData *td = static_cast<threadData*>(args);
//     const char* name = td->_threadname.c_str();
//     while (1)
//     {
//         // 线程对于锁的竞争能力可能会不同
//         pthread_mutex_lock(td->_lock);  // 申请锁成功，才能往后执行；不成功，阻塞等待
//         if (tickets > 0)
//         {
//             usleep(1000);  // 抢票花的时间
//             printf("%s get a ticket: %d\n", name, tickets);
//             tickets--;
//             pthread_mutex_unlock(td->_lock);  // 解锁
//         }
//         else
//         {
//             pthread_mutex_unlock(td->_lock);  // 解锁
//             break;
//         }
//         usleep(13);  // 我们抢到了票，会立马抢下一张吗？不会，其实多线程还要执行得到票之后的后续动作，用usleep模拟
//     }
//     printf("%s ... quit\n", name);

//     return nullptr;
// }

// int main()
// {
//     pthread_mutex_t lock;  // 锁也是一个变量，这是在main函数的栈上开辟的空间
//     pthread_mutex_init(&lock, nullptr);

//     vector<pthread_t> tids;
//     vector<threadData *> thread_datas;
//     for (int i = 1; i <= NUM; ++i)
//     {
//         pthread_t tid;
//         threadData *td = new threadData(i, &lock);
//         thread_datas.push_back(td);

//         pthread_create(&tid, nullptr, getTicket, td);
//         tids.push_back(tid);
//     }

//     for (auto thread : tids)
//     {
//         pthread_join(thread, nullptr);
//     }
//     for (auto td : thread_datas)
//     {
//         delete td;
//     }

//     pthread_mutex_destroy(&lock);
//     return 0;
// }
